#ifndef _SQ_DBGSERVER_H_
#define _SQ_DBGSERVER_H_

#define MAX_BP_PATH 512
#define MAX_MSG_LEN 2049
#define MAX_NESTING 10

#include <set>
#include <string>
#include <vector>
#include <winsock.h>

typedef std::basic_string<SQChar> SQDBGString;

inline bool dbg_less( const SQChar *x, const SQChar *y ) {
  int n = 0;
  do {
    int xl = *x == '\\' ? '/' : tolower( *x );
    int yl = *y == '\\' ? '/' : tolower( *y );
    int diff = xl - yl;
    if( diff != 0 ) {
      return diff > 0 ? true : false;
    }
    x++;
    y++;
  } while( *x != 0 && *y != 0 );
  return false;
}

struct BreakPoint {
  BreakPoint() {_line = 0;}
  BreakPoint( int line, const SQChar *src ) { _line = line; _src = src; }
  BreakPoint( const BreakPoint& bp ) { _line = bp._line; _src = bp._src; }
  inline bool operator<( const BreakPoint& bp ) const {
    if( _line < bp._line ) {
      return true;
    }
    if( _line == bp._line ) {
      return dbg_less( _src.c_str(), bp._src.c_str() );
    }
    return false;
  }

  int _line;
  SQDBGString _src;
};

struct Watch {
  Watch() { _id = 0; }
  Watch( int id, const SQChar *exp ) { _id = id; _exp = exp; }
  Watch( const Watch &w ) { _id = w._id; _exp = w._exp; }
  bool operator<( const Watch& w ) const { return _id < w._id; }
  bool operator==( const Watch& w ) const { return _id == w._id; }
  int _id;
  SQDBGString _exp;
};

typedef std::set<BreakPoint> BreakPointSet;
typedef BreakPointSet::iterator BreakPointSetItor;
typedef std::set<Watch> WatchSet;
typedef WatchSet::iterator WatchSetItor;
typedef std::vector<SQChar> SQCharVec;
struct SQDbgServer {
  public:
    enum eDbgState {
      eDBG_Running,
      eDBG_StepOver,
      eDBG_StepInto,
      eDBG_StepReturn,
      eDBG_Suspended,
      eDBG_Disabled,
    };

    SQDbgServer( HSQUIRRELVM v );
    ~SQDbgServer();
    bool Init();
    bool WaitForClient();
    bool ReadMsg();
    void BusyWait();
    void Hook( int type, int line, const SQChar *src, const SQChar *func );
    void ParseMsg( const char *msg );
    bool ParseBreakpoint( const char *msg, BreakPoint &out );
    bool ParseWatch( const char *msg, Watch &out );
    bool ParseRemoveWatch( const char *msg, int &id );
    void Terminated();
    void BreakExecution();
    void Send( const SQChar *s, ... );
    void SendChunk( const SQChar *chunk );
    void Break( int line, const SQChar *src, const SQChar *type, const SQChar *error = NULL );
    void SerializeState();
    void AddBreakpoint( BreakPoint &bp );
    void AddWatch( Watch &w );
    void RemoveWatch( int id );
    void RemoveBreakpoint( BreakPoint &bp );
    void SetErrorHandlers();
    struct XMLElementState {
      SQChar name[256];
      bool haschildren;
    };

    XMLElementState xmlstate[MAX_NESTING];
    int _xmlcurrentement;
    void BeginDocument() { _xmlcurrentement = -1; }
    void BeginElement( const SQChar *name );
    void Attribute( const SQChar *name, const SQChar *value );
    void EndElement( const SQChar *name );
    void EndDocument();
    const SQChar *escape_xml( const SQChar *x );
    HSQUIRRELVM _v;
    HSQOBJECT _debugroot;
    eDbgState _state;
    SOCKET _accept;
    SOCKET _endpoint;
    BreakPointSet _breakpoints;
    WatchSet _watches;
    int _recursionlevel;
    int _maxrecursion;
    int _nestedcalls;
    bool _ready;
    bool _autoupdate;
    HSQOBJECT _serializefunc;
    SQCharVec _scratchstring;

};
#define sqdbg_closesocket(x) close((x))
#endif
